package io.gitee.sfch.chunmi.auth.session;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.gitee.sfch.chunmi.auth.AuthenticationService;
import io.gitee.sfch.chunmi.auth.SkipAuthentication;
import io.gitee.sfch.chunmi.entity.Response;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;

/**
 * 鉴权拦截器，该类将在请求进入前对请求进行校验，当开启拦截校验（默认开启），并且目标类或方法上未注解跳过校验时，
 * 将根据请求中的cookie获取session，存在session表示登录，未登录时按统一响应格式返回失败信息
 */
@Slf4j
@Component
public class AuthenticationInterceptor implements HandlerInterceptor, InitializingBean {

    @Resource
    private AuthenticationService authenticationService;
    @Resource
    private ObjectMapper objectMapper;

    /**
     * 未登录的JSON字符串响应值
     */
    private String unLoginJsonStingResponse;

    /**
     * 使用{@link ObjectMapper}初始化未登录的JSON字符串响应值
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        unLoginJsonStingResponse = objectMapper.writeValueAsString(Response.failEmpty("未登录"));
    }

    @Override
    public boolean preHandle(@Nonnull HttpServletRequest request, @Nonnull HttpServletResponse response,
                             @Nonnull Object handler) throws IOException {
        if (handler instanceof HandlerMethod methodHandler) {
            Method method = methodHandler.getMethod();
            // 检查对应的方法是否有@SkipAuth注解
            if (method.isAnnotationPresent(SkipAuthentication.class)) {
                return true;
            }
            // 检查类级别是否有@SkipAuth注解
            if (method.getDeclaringClass().isAnnotationPresent(SkipAuthentication.class)) {
                return true;
            }
        }

        boolean isLogin = authenticationService.alreadyLogin(request);
        if (!isLogin) {
            // 未登录时，返回未鉴权401
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            response.setCharacterEncoding(StandardCharsets.UTF_8.name());
            response.getWriter().write(unLoginJsonStingResponse);
        }
        return isLogin;
    }

}
